package com.myzhouye.biz.controller;/***
 *                    _ooOoo_
 *                   o8888888o
 *                   88" . "88
 *                   (| -_- |)
 *                    O\ = /O
 *                ____/`---'\____
 *              .   ' \\| |// `.
 *               / \\||| : |||// \
 *             / _||||| -:- |||||- \
 *               | | \\\ - /// | |
 *             | \_| ''\---/'' | |
 *              \ .-\__ `-` ___/-. /
 *           ___`. .' /--.--\ `. . __
 *        ."" '< `.___\_<|>_/___.' >'"".
 *       | | : `- \`.;`\ _ /`;.`/ - ` : | |
 *         \ \ `-. \_ __\ /__ _/ .-` / /
 * ======`-.____`-.___\_____/___.-`____.-'======
 *                    `=---='
 *
 * .............................................
 *          佛祖保佑             永无BUG
 */

/**
 * @program: game01
 * @description:
 * @author: 那条蠢鱼
 * @create: 2025-11-05 17:14
 **/

import com.myzhouye.biz.bean.LoginUser;
import com.myzhouye.biz.bean.R;
import com.myzhouye.biz.dto.params.LoginRequest;
import com.myzhouye.biz.model.User;
import com.myzhouye.biz.repository.UserRepository;
import com.myzhouye.biz.security.RedisTokenUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

/**
 * 用户认证接口（登录/注销）
 */
@RestController
@RequestMapping("/auth")
@Tag(name = "用户认证", description = "登录、注销接口")
@RequiredArgsConstructor
public class AuthController {
    // 添加：多登录配置属性:0=允许重复登录,1=不允许重复登录,2=已登录则返回现有token
    @Value("${sys.config.allow_mutl_login:2}")
    private int allowMutlLogin;


    private final ReactiveAuthenticationManager authenticationManager;
    private final RedisTokenUtils tokenUtils;
    private final UserRepository userService;

    /**
     * 用户登录接口（纯响应式实现）
     */
    @PostMapping("/login")
    @Operation(summary = "用户登录")
    public Mono<R<?>> login(
            @RequestBody @Schema(description = "登录请求参数") LoginRequest loginRequest
    ) {
        // 1. 构建认证令牌
        UsernamePasswordAuthenticationToken authToken =
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());

        // 2. 响应式认证流程
        return authenticationManager.authenticate(authToken)
                .flatMap(authentication -> {
                    LoginUser loginUser = (LoginUser) authentication.getPrincipal();


                    // 添加：多登录控制逻辑
                    if (allowMutlLogin != 0) {
                        // 查询用户是否已有登录token
                        return tokenUtils.findExistingTokenByUserId(loginUser.getUserId())
                                .flatMap(existingToken -> {
                                    if (allowMutlLogin == 1) {
                                        // 配置1：已登录则提示失败
                                        return Mono.just(R.failed("账号已在其他地方登录，不允许重复登录"));
                                    } else {
                                        // 配置2：已登录则返回现有token
                                        return Mono.just(R.ok(existingToken));
                                    }
                                })
                                // 没有现有token，继续生成新token
                                .switchIfEmpty(generateNewToken(loginUser));
                    } else {
                        // 配置0：直接生成新token
                        return generateNewToken(loginUser);
                    }
                })
                .onErrorResume(e -> Mono.just(R.failed("用户名或密码错误")))
                .switchIfEmpty(Mono.just(R.failed("用户不存在或认证失败")));
    }

    /**
     * 用户注销接口（纯响应式实现）
     */
    @PostMapping("/logout")
    @Operation(summary = "用户注销")
    public Mono<R<Boolean>> logout(@RequestHeader("Authorization") String token) {
        String actualToken = token.replace("Bearer ", "");
        return tokenUtils.invalidateToken(actualToken) // 从Redis删除Token
                .map(success -> R.ok(success))
                .switchIfEmpty(Mono.just(R.failed("Token不存在")));
    }

    // 添加：抽取生成新token的逻辑为私有方法
    private Mono<R<String>> generateNewToken(LoginUser loginUser) {
        return Mono.justOrEmpty(userService.findById(loginUser.getUserId()))
                .flatMap(user ->
                        tokenUtils.generateToken(user, loginUser.getAuthorities())
                                .map(token -> R.ok(token))
                );
    }
}
